﻿using System;
using System.Collections.Specialized;
using System.Linq;
using System.Web;

namespace Trentacular.SharePoint.Features.Util
{
    public static class UrlUtils
    {
        public static string AppendQueryString(string url, NameValueCollection queryString)
        {
            var query = StringUtils.Delimit(queryString.AllKeys.Select(k => string.Format("{0}={1}",
                HttpUtility.UrlEncode(k),
                HttpUtility.UrlEncode(queryString[k]))
                ),
                "&");

            if (string.IsNullOrEmpty(query))
                return url;

            string delimiter = url.Contains("?") ? "&" : "?";
            return string.Format("{0}{1}{2}", url, delimiter, query);
        }

        public static string AppendQueryStringPair(string url, string key, string value)
        {
            string delimiter = url.Contains("?") ? "&" : "?";

            return string.Format("{0}{1}{2}={3}",
                url,
                delimiter,
                HttpUtility.UrlEncode(key),
                HttpUtility.UrlEncode(value));
        }

        public static string StripQueryAndHash(string url)
        {
            int queryIndex = url.IndexOf('?');
            if (queryIndex >= 0)
                url = url.Remove(queryIndex);

            int hashIndex = url.IndexOf('#');
            if (hashIndex >= 0)
                url = url.Remove(hashIndex);

            return url;
        }

        public static string GetVirtualUrl(this HttpRequest request)
        {
            string virtualUrl = request.RawUrl.Substring(request.ApplicationPath.Length);
            if (virtualUrl[0] != '/')
                virtualUrl = virtualUrl.Insert(0, "~/");
            else
                virtualUrl = virtualUrl.Insert(0, "~");
            return virtualUrl;
        }

        public static string GetAbsoluteApplicationPath(this HttpRequest request)
        {
            return string.Format("{0}://{1}{2}", request.Url.Scheme, request.Url.Host, request.ApplicationPath.TrimEnd('/'));
        }

        public static Uri GetOriginalUri(this HttpRequest request)
        {
            return new Uri(request.Url, request.RawUrl);
        }

        public static NameValueCollection GenerateQueryStringCollection(string url)
        {
            NameValueCollection queryString = new NameValueCollection();

            int queryIndex = url.IndexOf('?');
            if (queryIndex < 0)
                return queryString;

            string query = url.Substring(queryIndex + 1);
            int hashIndex = query.IndexOf('#');
            if (hashIndex >= 0)
                query = query.Substring(0, hashIndex);

            int chars = query.Length;
            for (int i = 0; i < chars; i++)
            {
                int startIndex = i;
                int sepIndex = -1;
                while (i < chars)
                {
                    char ch = query[i];
                    if (ch == '=')
                    {
                        if (sepIndex < 0)
                        {
                            sepIndex = i;
                        }
                    }
                    else if (ch == '&')
                    {
                        break;
                    }
                    i++;
                }

                string name = null;
                string value = null;
                if (sepIndex >= 0)
                {
                    name = query.Substring(startIndex, sepIndex - startIndex);
                    value = query.Substring(sepIndex + 1, (i - sepIndex) - 1);
                }
                else
                {
                    value = query.Substring(startIndex, i - startIndex);
                }

                queryString.Add(HttpUtility.UrlDecode(name), HttpUtility.UrlDecode(value));

                if ((i == (chars - 1)) && (query[i] == '&'))
                {
                    queryString.Add(null, string.Empty);
                }
            }

            return queryString;
        }

        public static string EncodeSpaces(string url)
        {
            return url.Replace(" ", "%20");
        }

        public static StringDictionary UrlSpecialCharacters;
        static UrlUtils()
        {
            UrlSpecialCharacters = new StringDictionary();
            UrlSpecialCharacters.Add("$", "%24");
            UrlSpecialCharacters.Add("&", "%26");
            UrlSpecialCharacters.Add("+", "%2B");
            UrlSpecialCharacters.Add(",", "%2C");
            UrlSpecialCharacters.Add("/", "%2F");
            UrlSpecialCharacters.Add(":", "%3A");
            UrlSpecialCharacters.Add(";", "%3B");
            UrlSpecialCharacters.Add("=", "%3D");
            UrlSpecialCharacters.Add("?", "%3F");
            UrlSpecialCharacters.Add("@", "%40");
            UrlSpecialCharacters.Add(" ", "%20");
            UrlSpecialCharacters.Add("\"", "%22");
            UrlSpecialCharacters.Add("<", "%3C");
            UrlSpecialCharacters.Add(">", "%3E");
            UrlSpecialCharacters.Add("#", "%23");
            UrlSpecialCharacters.Add("%", "%25");
            UrlSpecialCharacters.Add("{", "%7B");
            UrlSpecialCharacters.Add("}", "%7D");
            UrlSpecialCharacters.Add("|", "%2C");
            UrlSpecialCharacters.Add("\\", "%5C");
            UrlSpecialCharacters.Add("^", "%5E");
            UrlSpecialCharacters.Add("~", "%7E");
            UrlSpecialCharacters.Add("[", "%5B");
            UrlSpecialCharacters.Add("]", "%5D");
            UrlSpecialCharacters.Add("`", "%60");
        }

        public static string ToUrlSafeString(string text)
        {
            foreach (string specialChar in UrlSpecialCharacters.Keys)
            {
                text = text.Replace(specialChar, UrlSpecialCharacters[specialChar]);
            }
            return text;
        }

        public static string FromUrlSafeString(string text)
        {
            foreach (string specialChar in UrlSpecialCharacters.Keys)
            {
                text = text.Replace(UrlSpecialCharacters[specialChar], specialChar);
            }
            return text;
        }

        public static string ToUrlSafeBase64String(byte[] data)
        {
            return Convert.ToBase64String(data)
                .Replace('+', '-')
                .Replace('/', '_')
                .Replace('=', ',');
        }

        public static byte[] FromUrlSafeBase64String(string text)
        {
            return Convert.FromBase64String(text
                    .Replace('-', '+')
                    .Replace('_', '/')
                    .Replace(',', '=')
                );
        }

        public static bool IsVirtualPath(string path)
        {
            return path.StartsWith("~");
        }
    }
}
